const Service = require('egg').Service;
const dayjs = require('dayjs')
const { DATE_FUZZY_FORMAT } = require('../constant/constant');

class CalculateService extends Service {

    // 查询车辆基本信息表
    async searchCarBasic() {
        const { jianghuKnex } = this.app
        const carBasic = await jianghuKnex('basic').select()
        const allCarNumber = carBasic.length
        let requiredInspectCar = 0;
        let underRepairCar = 0
        carBasic.forEach(row => {
            const remindDay = Math.ceil((dayjs(row.InspectValidityEndDate) - dayjs()) / (3600 * 1000 * 24))
            if (!isNaN(remindDay) && remindDay <= 0) {
                requiredInspectCar += 1;
            }
            if (row.operationStatus === '不可用' && row.notOperationReason === '维修中') {
                underRepairCar += 1;
            }
        })
        return { allCarNumber, requiredInspectCar, underRepairCar }
    }

    async searchViolation() {
        const { jianghuKnex } = this.app
        const violation = await jianghuKnex('violation').select()
        const violationCar = violation.length
        return violationCar
    }

    async searchInsurance() {
        const { jianghuKnex } = this.app
        // TODO:可与前端计算剩余日期的方法合并
        const insurance = await jianghuKnex('insurance').select()
        let needRenewalInsurance = 0;
        insurance.forEach(item => {
            const trafficRemindMilliseconds = dayjs(item.trafficEndDate) - dayjs()
            const trafficRemindDays = Math.ceil(trafficRemindMilliseconds / (3600 * 1000 * 24))
            const commercialRemindMilliseconds = dayjs(item.commercialEndDate) - dayjs()
            const commercialRemindDays = Math.ceil(commercialRemindMilliseconds / (3600 * 1000 * 24))
            if (trafficRemindDays <= 0 || commercialRemindDays <= 0) {
                needRenewalInsurance += 1
            }
        })
        return needRenewalInsurance
    }

    async searchContract() {
        const { jianghuKnex } = this.app
        const leaseCar = (await jianghuKnex('contract').select()).length
        // TODO:已出租的车辆未修改可用状态
        const unLeaseCar = (await jianghuKnex('basic').where({ operationStatus: "可用" }).select()).length
        return { leaseCar, unLeaseCar }
    }

    async searchCustomer() {
        const { jianghuKnex, knex } = this.app
        const allCustomer = (await jianghuKnex('customer').select()).length
        const leaseCustomer = (await knex('contract').countDistinct('customerId'))[0]['count(distinct `customerId`)']
        return { allCustomer, leaseCustomer }
    }

    /**
    * 风险情况、运营情况
    */
    async calculateNumSquare() {
        // 计算违章车辆
        const violationCar = await this.searchViolation()
        // 计算需续保车辆
        const needRenewalInsurance = await this.searchInsurance()
        // 计算逾期客户:根据合同每月计划表的下次交租金日期来判断
        const overdueCustomers = 0;
        // 计算全部车辆
        // 计算在修车辆
        // 计算需年检车辆
        const { allCarNumber, requiredInspectCar, underRepairCar } = await this.searchCarBasic()
        // 计算已租车辆
        // 计算未租车辆
        const { leaseCar, unLeaseCar } = await this.searchContract()
        // 计算全部客户
        // 计算已租客户
        const { allCustomer, leaseCustomer } = await this.searchCustomer()
        return { violationCar, needRenewalInsurance, overdueCustomers, allCarNumber, requiredInspectCar, underRepairCar, leaseCar, unLeaseCar, allCustomer, leaseCustomer }
    }

    // 折线图
    async suppleOneWeekDate(startDate, endDate) {
        let week = []
        let date = startDate
        // 转换为时间戳方便比较大小
        let start = dayjs(startDate).valueOf()
        let end = dayjs(endDate).valueOf()
        while (start <= end) {
            week.push(date)
            date = dayjs(date).add(1, 'day').format(DATE_FUZZY_FORMAT)
            start = dayjs(date).valueOf()
        }
        return week
    }

    async getCarNumber(type, week) {
        const { jianghuKnex } = this.app
        const rows = await jianghuKnex.raw(`select count(*) as dispatchCarNumber,Date(dispatchDate) as date from dispatch where dispatchStatus = '${type}' group by dispatchDate`);
        // 返回结果为一数组,需取出其中的字段
        const hasValueDate = rows[0].map(obj => dayjs(obj.date).format(DATE_FUZZY_FORMAT))
        const dispatchNumberOfHasValueDate = rows[0].map(obj => obj.dispatchCarNumber)
        let map = new Map()
        for (let index in hasValueDate) {
            map.set(hasValueDate[index], dispatchNumberOfHasValueDate[index])
        }
        let carNumber = week.map(date => {
            if (map.has(date)) {
                return map.get(date)
            } else {
                return 0;
            }
        })
        return carNumber
    }

    async getAmount(type, week) {
        const { jianghuKnex } = this.app
        const rows = await jianghuKnex.raw(`select sum(flowAmount) as flowAmount,Date(flowDate) as date from flow where flowType = '${type}' group by flowDate`);

        // knex查询出来的日期回比数据库少8个钟，用dayjs转换后即可
        const hasValueDate = rows[0].map(obj => dayjs(obj.date).format(DATE_FUZZY_FORMAT))
        const flowAmountOfHasValueDate = rows[0].map(obj => obj.flowAmount)
        let map = new Map()
        for (let index in hasValueDate) {
            map.set(hasValueDate[index], flowAmountOfHasValueDate[index])
        }
        let flowAmount = week.map(date => {
            if (map.has(date)) {
                return map.get(date)
            } else {
                return 0;
            }
        })
        return flowAmount
    }

    async dispatchAndReturnCarCalculate(actionData) {
        const { startDate, endDate } = actionData
        // 补足一星期的日期
        const week = await this.suppleOneWeekDate(startDate, endDate);

        // 获取一星期的发车量
        const dispatchCarNumber = await this.getCarNumber('发车', week)

        // 获取一星期的推车量
        const returnCarNumber = await this.getCarNumber('退车', week)

        const res = {
            week,
            dispatchCarNumber,
            returnCarNumber
        }
        return res;
    }

    async collectionAndPaymentCalculate(actionData) {
        const { startDate, endDate } = actionData
        // 补足一星期的日期
        const week = await this.suppleOneWeekDate(startDate, endDate);
        // 获取一星期的收款
        const collectionAmount = await this.getAmount('收款申请', week)
        // 获取一星期的付款
        const paymentAmount = await this.getAmount('付款申请', week)

        const res = {
            week,
            collectionAmount,
            paymentAmount
        }
        console.log(res)
        return res;
    }

}
module.exports = CalculateService;